using Game.Networking.Server;
using UnityEngine;
using NaughtyAttributes;
using Game.Networking.Client;
using MemoryPack;

namespace Game.Networking {
	public abstract class Entity<T> : Entity where T : EntityState, new() {
		public override EntityState Save() {
			return SaveInternal();
		}

		protected virtual T SaveInternal() {
			var state = new T();
			state.ID = ID;
			state.Type = EntityType;
			return state;
		}
	}

	public abstract class Entity : MonoBehaviour {
		public uint ID;
		protected bool IsServer;

		public abstract EntityType EntityType { get; }

		public bool IsEntityAlive { get; protected set; }

		public virtual void ApplyFullState(EntityState state) {
			ID = state.ID;
		}

		public string GetSummary() {
			if ( string.IsNullOrEmpty(_summary) ) {
				_summary = CreateSummary();
			}
			return _summary;
		}

		public Rigidbody Rb => _rb;

		public abstract EntityState Save();

		Rigidbody _rb;

		protected string _summary;

		public virtual void Create() {
			IsServer = GameManager.Instance.IsServer;
			IsEntityAlive = true;
			_rb = GetComponent<Rigidbody>();
			InitSyncVars();
		}

		[EnableIf("IsServer")]
		[Button("Destroy", EButtonEnableMode.Playmode)]
		public virtual void DestroyEntity() {		
			if ( IsServer && IsEntityAlive ) {
				IsEntityAlive = false;
				SDestroy_Internal();
				ServerEntityController.Instance.DestroyEntity( this );
			} else if ( IsEntityAlive ) {
				IsEntityAlive = false;
				CDestroy_Internal();
				ClientEntityController.Instance.DespawnEntity(ID);
			}
		}

		protected abstract string CreateSummary();

		protected virtual void SDestroy_Internal() {
			if ( !this ) {
				return;
			}
			Destroy(gameObject);
		}

		protected virtual void CDestroy_Internal() {
			if ( !this ) {
				return;
			}
			Destroy(gameObject);
		}

		public virtual void Tick(float currentTime, float deltaTime) {
		}

		public virtual void NetTick() {
			CheckSyncVars();
		}

		public virtual void Client_CallRPC(byte id, byte[] args) {
		}

		public virtual void Client_UpdateSyncVar(byte id, byte[] args) { }

		protected virtual void InitSyncVars() { }

		protected virtual void CheckSyncVars() { }
	}
}
